//bind主要将函数绑定到某个对象， 会创建一个函数 函数体内的this对象的值会被绑定到传入bind第一个参数的值

const a = {
    b:function(){
        return (function(){
            console.log(this.c);
        })()
        
    },
    c:'hello'
}
a.b();//输出undefined
// 这里面的this指向的全局作用域 (a在全局中调用 ) 可以用箭头函数代替或这用下面的
const a2 = {
    b:function(){
        var that = this
        return (function(){
            console.log(that.c);
        })()
        
    },
    c:'hello2'
}
a2.b();//hello2

const a3 = {
    b:function(){
       
        return (function(){
            console.log(this.c);
        }).bind(this)()
        
    },
    c:'hello3'
}
a3.b()

//另一种用法
function f(y,z){
    return this.x + y + z;
}
var m = f.bind({x:1},2);
console.log(m(3));//6
//这里的bind方法会把它的第一个实参绑定给f函数体内的this 所以这里this即指向{x：1}
//从第二个参数起 会一次传递给原始函数 执行结果为1+2+3 = 6 分布处理参数的过程其实是一个典型的函数柯里化的过程

function list(){
        return Array.prototype.slice.call(arguments);
    }
    var list1 = list(1, 2, 3);
    //[1, 2, 3]
     
    //预定义参数
    var aa = list.bind(undefined, 10);
     
    var list2 = aa(8);
    console.log(list2)
    //[10]
     
    var list3 = aa(1, 2, 3);
    console.log(list3)
    //[10, 1, 2, 3]

    //自己实现bind函数
    //最简单的实现无法传参
    Function.prototype.my_bind =  function(context){
        let self = this;
        return ()=>{
            console.log(self,this)
            return this.apply(context,arguments);
        }
    }
    //测试
    function aaa(){
        return this.name;
    }
    var bbb = {name:"空"}
    console.log(aaa.bind(bbb)())
    console.log(aaa.my_bind(bbb)())

//my_bind方法不仅可以绑定对象，还可以传参
Function.prototype.my_bind2 = function(context){
        var args = Array.prototype.slice.call(arguments,1);
        //args [7, 8]
        console.log(args,'args')
        var self = this;
        return function(){
            var innerArgs = Array.prototype.slice.call(arguments);
            //innerArgs [9]
            console.log(innerArgs,'innerArgs')
            var finalArgs = args.concat(innerArgs);
            //finalArgs [7, 8, 9]
            console.log(self,context)
            return self.apply(context, finalArgs);
        }
    }
     
    //测试
    function aaa2(m, n, o){
        return this.name + ' ' + m + ' ' + n + ' ' + o;
    }
     
    var bbb2 = {name : 'kong'};
     
    console.log(aaa2.my_bind2(bbb2, 7, 8)(9));        //kong 7 8 9

    //处理bind返回的函数如果作为构造函数，搭配new关键字出现的话，我们绑定的this就需要被忽略的兼容性问题
    Function.prototype.bindb =  function(context){
        
        //确保调用bind方法的一定要是一个函数
        if(typeof this !== "function"){
            throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
        }
        var args = Array.prototype.slice.call(arguments, 1);
        console.log(Array.prototype.slice.call(arguments),args,'ssafafsf')
        var self = this;
        var F = function(){};
        F.prototype = this.prototype;
        var bound = function(){
            var innerArgs = Array.prototype.slice.call(arguments);
            var finalArgs =args.concat(innerArgs)
            console.log(innerArgs,7894989,finalArgs,this instanceof F)

            return self.apply(this instanceof F ? this : context || this, finalArgs);
        }
        bound.prototype = new F();
        return bound;

    }
    var test = {name:'完善？'}
    function testWan(){
        console.log(arguments,this.name,'kkk')
    }
    let Low = testWan.bindb(test,7,8)
    let wow = new Low(10)
 

    
